<html>
<body>\documentclass{article}
\usepackage{hyperref}
\usepackage{graphicx}
\usepackage{listings}
\usepackage{csquotes}
\begin{document}

\section{Terminal Markdown Viewer}

<table>

<tr><td>foo</td></tr>

<tr><td>foo</td></tr>

<tr><td>foo</td></tr>

<tr><td>foo</td></tr>

</table>

\href{https://travis-ci.org/axiros/terminal_markdown_viewer}{
\includegraphics{https://travis-ci.org/axiros/terminal_markdown_viewer.svg?branch=master}
}
<a href='https://coveralls.io/github/axiros/terminal_markdown_viewer?branch=master'>
<img src='https://coveralls.io/repos/github/axiros/terminal_markdown_viewer/badge.svg?branch=master' alt='Coverage Status' /></a>
\href{https://badge.fury.io/py/mdv}{
\includegraphics{https://badge.fury.io/py/mdv.svg}
}
<a href="https://github.com/ambv/black"><img alt="Code style: black" src="https://img.shields.io/badge/code%20style-black-000000.svg"></a>

When you edit multiple md files remotely, like in a larger
\href{http://www.mkdocs.org/}{mkdocs} project, context switches between editing
terminal(s) and viewing browser may have some efficiency impact.
Also sometimes there is just no browser, like via security gateways offering
just a fixed set of applications on the hop in machine.
Further, reading efficiency and convenience is often significantly improved
by using colors.
And lastly, using such a thing for cli applications might improve user output,
e.g. for help texts.

This is where mdv, a Python based Markdown viewer for the terminal might be
a good option.

<!-- toc -->
\begin{itemize}
\item 
\href{#terminal-markdown-viewer}{Terminal Markdown Viewer}
\begin{itemize}
\item 
\href{#features}{Features}

\item 
\href{#alternatives}{Alternatives}

\item 
\href{#installation}{Installation}

\item 
\href{#usage}{Usage}
\begin{itemize}
\item 
\href{#cli}{CLI}

\item 
\href{#inline}{Inline}

\item 
\href{#sample-inline-use-case-click-module-docu}{Sample Inline Use Case: click module docu}

\end{itemize}

\item 
\href{#customization}{Customization}

\item 
\href{#screenshots}{Screenshots}

\item 
\href{#todo}{TODO}

\item 
\href{#credits}{Credits}

\item 
\href{#updates}{Updates}

\end{itemize}

\end{itemize}

<!-- tocstop -->

If markdown is often "simple" enough to be somewhat readable on 256 color terminals (except images that is).

<img src="./samples/1.png" width=500>

from

\begin{lstlisting}[language=]
### Source
# Header 1
## Header 2
### Header 3
#### Header 4
##### Header 5
###### Header 6
```python
""" Test """
# Make Py2 >>> Py3:
import os, sys; reload(sys); sys.setdefaultencoding('utf-8')
# no? see http://stackoverflow.com/a/29832646/4583360 ...

# code analysis for hilite:
try:
    from pygments import lex, token
    from pygments.lexers import get_lexer_by_name, guess_lexer
```

| Tables | Fmt |
| -- | -- |
| !!! hint: wrapped | 0.1 **strong** |

!!! note: title
    this is a Note
\end{lstlisting}

You can also use mdv as a \textbf{source code} viewer, best when you have docstrings with markdown in your code:


\includegraphics{./samples/5.png}


from

\begin{lstlisting}[language=python]
~/terminal_markdown_viewer $ cat setup.py
#!/usr/bin/env python2.7
# coding: utf-8

"""_
# Mdv installation

## Usage

    [sudo] ./setup.py install

----
"""

from setuptools import setup, find_packages

import mdv

setup(
    name='mdv',
    version=mdv.__version__,

\end{lstlisting}

(the '_' after the docstring telling mdv that markdown follows)
\hrulefill
\begin{displayquote}

mdv is a proof of concept hack: While for simple structures it does its job quite well, for complex markdown you want to use other tools.
Especially for inlined html it simply fails.
\end{displayquote}
\hrulefill

\subsection{Features}
\begin{itemize}
\item 
Tons of theme combinations: mdv ships with > 200 luminocity sorted themes, converted from html themes tables to ansi. Those can be combined for code vs regular markdown output...

\item 
Admonitions

\item 
Tables, incl. wide table handling avoiding "interleaving"

\item 
Somewhat hackable, all in \href{mdv/markdownviewer.py}{one} module

\item 
Useable as lib as well

\item 
File change monitor

\item 
Text wrapping

\item 
Source code highlighter

\item 
Little directory change monitor (cames handy when working on multiple files, to get the current one always displayed)
\begin{itemize}
\item 
which can run arbitrary commands on file changes

\item 
which passes filepath, raw and prettyfied content to the other command
Note: Poor man's implementation, polling. Check inotify based tools if you want sth better.

\end{itemize}

\end{itemize}

\subsection{Alternatives}

The ones I know of (and which made me write mdv ;-) ):
\begin{enumerate}
\item 
There are quite a few from the js community (e.g. \href{https://www.npmjs.com/package/msee}{msee}, ansidown, ansimd and also nd which is great) but they require nodejs \& npm, which I don't have on my servers. Also I personally wanted table handling and admonition support throughout and prob. too old to hack other peoples' js (struggling enough with my own). But have a look at them, they do some things better than mdv in this early version (I try to learn from them). Also \href{https://github.com/substack/picture-tube}{this} would be worth a look ;-)

\item 
pandoc -> html -> elinks, lynx or pandoc -> groff -> man. (Heavy and hard to use from within other programs. Styling suboptimal)

\item 
vimcat (Also heavy and hard to use inline in other programs)

\end{enumerate}

Summary: For production ready robust markdown viewing (e.g. for your customers) I recommend nd still, due to the early state of mdv. For playing around, especially with theming or when with Python, this one might be a valid alternative to look at.

\subsection{Installation}

\begin{lstlisting}[language=]
pip install mdv
\end{lstlisting}

If you get \verb|no attribute HTML_PLACEHOLDER|: update your markdown package.

\href{https://trac.macports.org/ticket/53591}{Here} is a macport (thanks Aljaž).

\subsubsection{Manual Install: Requirements}
\begin{itemize}
\item 
python == 2.7 or > 3.5

\item 
py markdown (pip install markdown)

\item 
py pygments (pip install pygments)

\item 
py yaml (pip install pyyaml)

\item 
py docopt (pip install docopt)

\item 
py tabulate (pip install tabulate)

\end{itemize}

Further a 256 color terminal (for now best with dark background) and font support for a few special separator characters (which you could change via config).
\begin{displayquote}

For light terms you'd just need to revert the 5 colors from the themes, since they are sorted by luminocity.
\end{displayquote}

I did not test anything on windows.

\subsubsection{Manual Install: Setup}

Distribution via setuptools. If setuptools is not installed, run:

\begin{lstlisting}[language=]
pip install setuptools
\end{lstlisting}

Use the setup.py provided inside, I.e. run:

\begin{lstlisting}[language=]
sudo ./setup.py install
(or ./setup.py install --user to install only for the current user)
\end{lstlisting}

\subsection{Usage}

\subsubsection{CLI}

\begin{lstlisting}[language=markdown]

# Usage:

    mdv [OPTIONS] MDFILE

# Options:

    MDFILE    : Path to markdown file
    -A        : Strip all ansi (no colors then)
    -C MODE   : Sourcecode highlighting mode
    -H        : Print html version
    -L        : Backwards compatible shortcut for '-u i'
    -M DIR    : Monitor directory for markdown file changes
    -T C_THEME: Theme for code highlight. If not set: Using THEME.
    -X Lexer  : Default lexer name (default: python). Set -x to use it always.
    -b TABL   : Set tab_length to sth. different than 4 [default: 4]
    -c COLS   : Fix columns to this (default: your terminal width)
    -f FROM   : Display FROM given substring of the file.
    -h        : Show help
    -i        : Show theme infos with output
    -l        : Light background (not yet supported)
    -m        : Monitor file for changes and redisplay FROM given substring
    -n NRS    : Header numbering (default: off. Say e.g. -3 or 1- or 1-5
    -t THEME  : Key within the color ansi_table.json. 'random' accepted.
    -u STYL   : Link Style (it=inline table=default, h=hide, i=inline)
    -x        : Do not try guess code lexer (guessing is a bit slow)


# Notes:

We use stty tool to derive terminal size. If you pipe into mdv we use 80 cols.

## To use mdv.py as lib:

Call the main function with markdown string at hand to get a
formatted one back. Sorry then for no Py3 support, accepting PRs if they don't screw Py2.

## FROM:

FROM may contain max lines to display, seperated by colon.
Example:

    -f 'Some Head:10' -> displays 10 lines after 'Some Head'

If the substring is not found we set it to the *first* character of the file -
resulting in output from the top (if your terminal height can be derived correctly through the stty cmd).

## Code Highlighting

Set -C <all|code|doc|mod> for source code highlighting of source code files.
Mark inline markdown with a '_' following the docstring beginnings.

- all: Show markdown docstrings AND code (default if you say, e.g. `-C.`)
- code: Only Code
- doc: Only docstrings with markdown
- mod: Only the module level docstring


## File Monitor:

If FROM is not found we display the whole file.

## Directory Monitor:

We check only text file changes, monitoring their size.

By default .md, .mdown, .markdown files are checked but you can change like `-M 'mydir:py,c,md,'` where the last empty substrings makes mdv also monitor any file w/o extension (like 'README').

### Running actions on changes:

If you append to `-M` a `'::<cmd>'` we run the command on any change detected (sync, in foreground).

The command can contain placeholders:

    _fp_     # Will be replaced with filepath
    _raw_    # Will be replaced with the base64 encoded raw content
               of the file
    _pretty_ # Will be replaced with the base64 encoded prettyfied output

Like: mdv -M './mydocs:py,md::open "_fp_"'  which calls the open
command with argument the path to the changed file.


## Themes

### Theme Rollers


    mdv -T all [file]:  All available code styles on the given file.
    mdv -t all [file]:  All available md   styles on the given file.
                        If file is not given we use a short sample file.

So to see all code hilite variations with a given theme:

Say C_THEME = all and fix THEME

Setting both to all will probably spin your beach ball...

### Environ Vars

`$MDV_THEME` and `$MDV_CODE_THEME` are understood, e.g. `export
MDV_THEME=729.8953` in your .bashrc will give you a consistent color scheme.


\end{lstlisting}
\begin{displayquote}

Regarding the strange theme ids: Those numbers are the calculated total luminocity of the 5 theme colors.
\end{displayquote}

\subsubsection{Inline}

mdv is designed to be used well from other (Py2) programs when they have md at hand which should be displayed to the user:

\begin{lstlisting}[language=python]
import mdv

# config like this:
mdv.term_columns = 60

# calling like this (all CLI options supported, check def main
formatted = mdv.main(my_raw_markdown, c_theme=...)  
\end{lstlisting}
\begin{displayquote}

Note that I set the defaultencoding to utf-8  in \verb|__main__|. I have this as my default python2 setup and did not test inline usage w/o. Check \href{http://stackoverflow.com/a/29832646/4583360}{this} for risks.
\end{displayquote}

\subsubsection{Sample Inline Use Case: click module docu}

\href{http://lucumr.pocoo.org/2014/5/12/everything-about-unicode/}{Armin Ronacher}'s
\href{http://click.pocoo.org}{click} is a great framework for writing larger CLI apps - but its help texts are a bit boring, intended to be customized.

Here is how:

Write a normal click module with a function but w/o a doc string as shown:

\begin{lstlisting}[language=python]
@pass_context                                                                   
def cli(ctx, action, name, host, port, user, msg):           
	""" docu from module __doc__ """
\end{lstlisting}

On module level you provide markdown for it, like:

\begin{lstlisting}[language=shell]
~/axc/plugins/zodb_sub $ cat zodb.py | head
"""
# Fetch and push ZODB trees

## ACTION: < info | pull | push | merge | dump | serve>

- info:  Requests server availability information
(...)
\end{lstlisting}

which you set at click module import time:

\begin{lstlisting}[language=]
mod.cli.help = mod.__doc__
\end{lstlisting}

Lastly do this in your app module:

\begin{lstlisting}[language=python]
from click.formatting import HelpFormatter
def write_text(self, text):
    """ since for markdown pretty out on cli I found no good tool
	so I built my own """
    # poor man's md detection:
    if not text.strip().startswith('#'):
        return orig_write_text(self, text)
    from axc.markdown.mdv import main as mdv
    self.buffer.append(mdv(md=text, theme=os.environ['AXC_THEME']))

HelpFormatter.orig_write_text = HelpFormatter.write_text
HelpFormatter.write_text = write_text
\end{lstlisting}

The output has then colors:


\includegraphics{samples/3.png}


and at smaller terms rewraps nicely:


\includegraphics{samples/4.png}


Further, having markdown in the module \verb|__doc__| makes it simple to add into a global project docu framework, like mkdocs.

\subsection{Customization}

You can supply all CLI args in \verb|\$HOME/.mdv|, in yaml format.

More flex you have via \verb|\$HOME/.mdv.py|, which is execed if present, when
running \verb|main|.

Alternatively, in \href{mdv.py}{mdv.py} you can change some config straight forward.

\begin{lstlisting}[language=python]
# ---------------------------------------------------------------------- Config
txt_block_cut, code_pref, list_pref, br_ends = '✂', '| ', '- ', '◈'
# ansi cols (default):
# R: Red (warnings), L: low visi, BG: background, BGL: background light, C=code
# H1 - H5 = the theme, the numbers are the ansi color codes:
H1,  H2,  H3,  H4,  H5, R,   L,  BG, BGL, T,   TL, C   = \
231, 153, 117, 109, 65, 124, 59, 16, 188, 188, 59, 102
# Code (C is fallback if we have no lexer). Default: Same theme:
CH1, CH2, CH3, CH4, CH5 = H1, H2, H3, H4, H5

code_hl = { "Keyword" : 'CH3', "Name" : 'CH1',
            "Comment" : 'L',  "String": 'CH4',
            "Error"   : 'R',  "Number": 'CH4',
            "Operator": 'CH5',
            "Generic" : 'CH2'
            }

admons = {'note'     : 'H3', 'warning': 'R',
          'attention': 'H1', 'hint'   : 'H4',
          'summary'  : 'H1', 'hint'   : 'H4',
          'question' : 'H5', 'danger' : 'R',
          'caution'  : 'H2'
         }

def_lexer = 'python'
guess_lexer = True
# also global. but not in use, BG handling can get pretty involved...
background = BG

# normal text color:
color = T

show_links = None

# could be given, otherwise read from ansi_tables.json:
themes = {}


# sample for the theme roller feature:
md_sample = ''

# ------------------------------------------------------------------ End Config
\end{lstlisting}

Any importing module can overwrite those module global variables as well.

Should you need yet additional themes, add them to \verb|ansi_tables.json| file by adding your ansi codes there.

\subsection{Screenshots}

Random results, using the theme roller feature:


\includegraphics{https://github.com/axiros/terminal_markdown_viewer/blob/master/samples/2.png}


Note the table block splitting when the table does not fit (last picture).

\subsection{TODO}
\begin{itemize}
\item 
Refactor the implementation, using a config class

\item 
Lines separators not optimal (\href{https://www.npmjs.com/package/nd}{nd} does better)

\item 
Test light colorscheme

\item 
Dimming

\item 
A few grey scale and 8 color themes

\item 
Sorting of the json by luminance

\item 
Some themes have black as darkest color, change to dark grey

\item 
Common Mark instead of markdown

\end{itemize}

\subsection{Credits}

\href{http://pygments.org/}{pygments} (using their lexer)

\href{https://pypi.python.org/pypi/tabulate}{tabulate}

and, naturally, the \href{https://pythonhosted.org/Markdown/authors.html}{python markdown project}

Update: Next version will be CommonMark based though...

\subsection{Updates}

\subsubsection{July 2016:}

Sort of an excuse for the long long time w/o an update:
I did actually start working on a more solid version based on CommonMark but
that went a bit out of scope, into a general html terminal viewer, which will
probably never be finished :-/

So at least here an update containing the stuff you guys sent as PRs, thanks all!!
\begin{itemize}
\item 
installation and dependencies via a setup.py (thanks
\href{https://github.com/althonos}{Martin})

\item 
supporting \verb|echo -e "\# foo\n\#\# bar" | mdv -| and a 'light' theme (thanks
\href{https://github.com/seletskiy}{Stanislav})

\item 
and a few other improvements regarding python2.7, file location and pyyaml, thanks all.

\end{itemize}

Also:
\begin{itemize}
\item 
fixed the most obvious bugs with nested ordered and unordered lists

\item 
fixed bold marker

\item 
different color highlighting for the list markers

\item 
added a source code highlighting mode, which highlights also docstrings in markdown (\verb|-C <mode>|)

\item 
some tests in the tests folder

\item 
using \verb|textwrap| now for the wrapping, to avoid these word breaks a few complained about

\item 
you can supply the default lexer now, e.g. \verb|-X javascript [-x]|

\item 
fixed but with not rendered strong texts

\item 
pip install mdv

\end{itemize}

\subsubsection{Nov 2016:}
\begin{itemize}
\item 
travis

\item 
Inline link tables

\end{itemize}


\includegraphics{samples/links.png}


\subsubsection{Sept 2018:}

foo\newline
bar ba
\begin{itemize}
\item 
Merged\newline
some PRs.

\item 
Decent \href{https://github.com/ambv/black}{code formatter}. Not that this weekend hack got more readable though. Well, maybe a bit.

\item 
Revised Py3 support (finally found peace with it, since they enforce UTF-8 everywhere the new features begin to outweigh the nightmares of trying to decode everything without need).

\item 
Indented code in PY3 was broken, fixed that. \textit{Why, PY3, are you you creating crap like "b'foo'" instead raising or auto-decoding?}

\item 
Header numbering feature added (\verb|-n 2-4| or \verb|-n 1-|)
<img src="./samples/header_num.png" width="400"/>

\end{itemize}

tabletest
\begin{tabular}{l l}
Date & foo
\hline
User & Any
Campaign & Any
Support Portal & \verb|[cpeid, '=', a cpeid]|
\end{tabular}
\end{document}
</body></html>